package com.poem.springboot_rear.controller;

import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.poem.springboot_rear.common.LogAs;
import com.poem.springboot_rear.common.LogType;
import com.poem.springboot_rear.common.Result;
import com.poem.springboot_rear.entity.User;
import com.poem.springboot_rear.exception.ServiceException;
import com.poem.springboot_rear.service.UserService;
import com.poem.springboot_rear.utils.TokenUtils;
import com.poem.springboot_rear.vo.MenuVo;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 功能
 * 作者：小祝小祝
 * 日期： 2023/11/12 20:54
 */
@CrossOrigin
@RestController
@RequestMapping("/user")  // 一级路由
public class UserController {

    @Resource
    UserService userService;

    /**
     * 新增用户信息
     */
    @LogAs(operation = "新增用户信息", type = LogType.ADD)
    @PostMapping("/add")
    public Result add(@RequestBody User user) {
        // try catch 捕获异常
        try {
            userService.save(user);
        } catch (Exception e) {
            // 判断异常的类型，然后返回不同的提示信息
            if (e instanceof DuplicateKeyException) {
                return Result.error("插入数据库错误");
            } else {
                return Result.error("系统错误");
            }
        }
        return Result.success();
    }

    /**
     * 修改用户信息
     */
    @LogAs(operation = "修改用户信息", type = LogType.UPDATE)
    @PostMapping("/update")
    public Result update(@RequestBody User user) {
        // try catch 捕获异常
        try {
            userService.updateById(user);
        } catch (Exception e) {
            // 判断异常的类型，然后返回不同的提示信息
            if (e instanceof DuplicateKeyException) {
                return Result.error("插入数据库错误");
            } else {
                return Result.error("系统错误");
            }
        }
        return Result.success();
    }

    /**
     * 删除用户信息
     */
    @LogAs(operation = "删除用户信息", type = LogType.DELETE)
    @DeleteMapping("/delete/{id}")
    public Result delete(@PathVariable Integer id) {
        // 获取当前登录的用户信息
        User currentUser = TokenUtils.getCurrentUser();
        if (id.equals(currentUser.getId())) {
            throw new ServiceException("不能删除当前登录的用户");
        }
        userService.removeById(id);
        return Result.success();
    }

    /**
     * 批量删除用户信息
     */
    @LogAs(operation = "批量删除用户信息", type = LogType.BATCH_DELETE)
    @DeleteMapping("/delete/batch")
    public Result batchDelete(@RequestBody List<Integer> ids) {
        // 获取当前登录的用户信息
        User currentUser = TokenUtils.getCurrentUser();
        // contains（）方法是java中list集合中的一个方法，用于判断当前列表是否包含某个元素
        // 当前登录的用户信息不为空，并且id不为空，并且ids里不包含登录的id
        if (currentUser != null && currentUser.getId() != null && ids.contains(currentUser.getId())) {
            throw new ServiceException("不能删除当前登录的用户");
        }
        userService.removeBatchByIds(ids);
        return Result.success();
    }

    /**
     * 查询全部用户信息
     */
    @GetMapping("/selectAll")
    public Result selectAll() {
//        List<User> userList = userService.list();
        // select * from user order by id desc  把查到的信息倒序
        List<User> userList = userService.list(new QueryWrapper<User>().orderByDesc("id"));
        return Result.success(userList);
    }

    /**
     * 根据ID查询用户信息
     */
    @GetMapping("/selectById/{id}")
    public Result selectById(@PathVariable Integer id) {
        User user = userService.getById(id);
        return Result.success(user);
    }

    /**
     * 根据username name 分页模糊查询用户信息
     * PageIndex 当前页码
     * PageSize  每页多少行数据
     */
    @GetMapping("/selectByPage")
    public Result selectByPage(@RequestParam Integer pageIndex,
                               @RequestParam Integer pageSize,
                               @RequestParam String username,
                               @RequestParam Integer parentId,
                               @RequestParam String name) {
        // 转换类型用来判断
        String parent_id = String.valueOf(parentId);
//        System.out.println(parentId+"父级id");
//        System.out.println(parent_id+"父级id");
        // 条件构造器
        QueryWrapper<User> queryWrapper = new QueryWrapper<User>().orderByDesc("id");
        queryWrapper.like(StrUtil.isNotBlank(username), "username", username);
        queryWrapper.like(StrUtil.isNotBlank(name), "name", name);
        queryWrapper.like(StrUtil.isNotBlank(parent_id), "parent_id", parentId);
        // 上面这三句就相当于 select * from `user` where username like '%#{username}%' and name '%#{name}%') order by id desc
        Page<User> page = userService.page(new Page<>(pageIndex, pageSize), queryWrapper);
        System.out.println(page);
        return Result.success(page);
    }

    @GetMapping("/treeSelect")
    public Result treeSelect(){
        List<MenuVo> list = userService.loadTree();
        return Result.success(list);
    }

    /**
     * 批量导出数据
     * 当username和name有值的时候就以他们搜索的内容导出
     * (required = false)表示这个字段可以不传入
     */
    @GetMapping("/export")
    public void exportData(@RequestParam(required = false) String username,
                           @RequestParam(required = false) String name,
                           @RequestParam(required = false) String ids, // 1,2,3
                           HttpServletResponse response) throws IOException {
        // 通过hutool工具类创建writer
        ExcelWriter writer = ExcelUtil.getWriter(true);
        List<User> list;
        // 条件构造器
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        // 如果ids不为空
        if (StrUtil.isNotBlank(ids)) {
            // 第二种 根据多选的数据导出
            // ["1","2","3"]  => [1,2,3]  Arrays.stream把字符串数组转换为int数组
            // 把字符串数组使用split分割，然后组成一个map集合，然后再把map集合转为list数组
            List<Integer> idsArr1 = Arrays.stream(ids.split(",")).map(Integer::valueOf).collect(Collectors.toList());
            // in传入一个数据库字段名称
            // 查询数据库里id 的字段有没有idsArr1传过来的id，也就是我们在前端选中的行的id，如果有说明这个条件生效了
            // 或者就是说，把传过来的id在数据库进行查询，如果有就存储下来，没有就算了
            queryWrapper.in("id", idsArr1);
        } else {
            // 第一种 全部导出
            queryWrapper.like(StrUtil.isNotBlank(username), "username", username);
            queryWrapper.like(StrUtil.isNotBlank(name), "name", name);
            // 上面这两句就相当于 select * from `user` where username like '%#{username}%' and name '%#{name}%') order by id desc
        }
        list = userService.list(queryWrapper); // 查询当前user表的所有数据
        // 将查到的数据写出
        writer.write(list, true);

        // 设置文件头
        // 这个参数代表的是媒体类型,告诉浏览器是什么类型的文件  这里我们设置的是xlsx表格类型
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        // attachment以附件的形式下载  设置文件名，编码格式，文件后缀
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("用户信息表", "UTF-8") + ".xlsx");
        ServletOutputStream outputStream = response.getOutputStream();
        // 刷新然后关闭
        writer.flush(outputStream, true);
        writer.close();
        // 仅仅刷新缓冲区(一般写字符时用到,因为写字符时先进入缓冲区),然后将内存中的数据立刻写出(因为缓冲区是写满之后才会写出, 用flush()就不必等到缓冲区满,立刻写出)流对象还可以继续使用.
        outputStream.flush();
        // 关闭流对象. 关闭之后,流对象不可以继续使用.但是在关闭之前会刷新一次缓冲区.
        outputStream.close();
    }

    /**
     * 批量导入
     *
     * @param file 传入的excel文件对象
     * @return 导入结果
     * 一、获取流
     * 二、把流写到reader中去
     * 三、通过reader.readAll读出所有的数据
     * 四、写入数据到数据库
     */

    @PostMapping("/import")
    public Result importUser(MultipartFile file) throws IOException {
        // 获取上传文件file输入流并应用hutool ExcelUtil获取ExcelReader指定输入流和sheet
        // getInputStream() 返回InputStream读取文件的内容
        // 获取流 把流写到reader中去
        ExcelReader reader = ExcelUtil.getReader(file.getInputStream());
        // 通过reader.readAll读出所有的数据
        List<User> userList = reader.readAll(User.class);
        // 写入数据到数据库
        try {
            userService.saveBatch(userList);
        } catch (Exception e) {
            e.printStackTrace(); // 打印错误信息
            return Result.error("数据导入出错");
        }
        return Result.success();
    }
}
